var OS3Tabs = {};
// OS3Tabs._events = {};
OS3Tabs._int_events = {};
OS3Tabs._instances = {};

OS3Tabs._int_events [ 'hover' ] = function ( tabs, div )
{
	if ( tabs._curr_tab ) tabs._curr_tab.className = ( tabs._curr_tab == tabs._curr_tab_sel ? "sel" : "tab" );
	div.className = "tab_hover";
	tabs._curr_tab = div;
};

OS3Tabs._int_events [ 'out' ] = function ( tabs, div )
{
 	div.className = ( div == tabs._curr_tab_sel ? "sel" : "tab" );
};

OS3Tabs._int_events [ 'btn_down' ] = function ( tabs, div )
{
 	div.className = "btn_down";
};

OS3Tabs._int_events [ 'btn_up' ] = function ( tabs, div )
{
 	div.className = "btn_up";
};

OS3Tabs._int_events [ 'click' ] = function ( tabs, div )
{
	var d = tabs._tabs_ref [ div.id ];

	if ( ! d )
	{
		d = document.getElementById ( tabs._tabs_names_ref [ div.id ] );
		if ( d ) 
			tabs._tabs_ref [ div.id ] = d;
		else
		{
			console.warn ( "OS3Tabs: div: %s does not exist.", tabs._tabs_names_ref [ div.id ] );
			return;
		}
	}

	if ( ( tabs._curr_tab_sel ) && ( tabs._curr_tab_sel == tabs._curr_tab ) ) return;

	if ( tabs._curr_tab_sel ) tabs._curr_tab_sel.className = 'tab';

	tabs._curr_tab_sel = tabs._curr_tab;
	if ( tabs._curr_div_shown ) tabs._curr_div_shown.style.display = 'none';

	d.style.display = 'block';

	tabs._curr_div_shown = d;
	tabs._curr_tab.className = 'sel';
};

/*
This function is the event dispatcher
It takes:
	
	- event_name:	- Name of the event
	- instance	- Name of the instance
	- group_name	- Name of the group which is firing the event
	- pos		- Tab position which is firing the event
*/
OS3Tabs.evt = function ( div, event_name, instance, group_name, pos )
{
	var tabs = OS3Tabs._instances [ instance ];

	if ( div._disabled )
	{
		if ( tabs._events [ event_name + '_disabled' ] ) tabs._events [ event_name + '_disabled' ] ( tabs, event_name, div, tabs._curr_div_shown, pos, group_name );
		return;
	}

	if ( tabs._blocked_events [ event_name ] ) return;
	if ( OS3Tabs._int_events [ event_name ] ) OS3Tabs._int_events [ event_name ] ( tabs, div );
	if ( tabs._events [ event_name ] ) tabs._events [ event_name ] ( tabs, event_name, div, tabs._curr_div_shown, pos, group_name );

	// console.debug ( "Event: %s - instance: %s - group: %s, pos: %d", event_name, instance, group_name, pos );
};

OS3Tabs.get = function ( instance_name )
{
	return this._instances [ instance_name ];
};

OS3Tabs.instance = function ( prefix )
{
	this._prefix  = prefix;
	this._events  = {}; 
	this._blocked_events = {};		// Events that should not be called
	this._tabs    = { 'default' : [] };
	this._tabs_ref = {};
	this._tabs_names_ref = {};
	this._divs_ref = {};
	this._divs_html = [];			// Divs to be created
	this._group_names = [ 'default' ];	// Group names (in order)

	this._group_params = {
		'default' : {}
	};

	this._curr_group = this._tabs [ 'default' ];
	this._curr_group_name = 'default';

	this.tab_width = 0;
	this.tab_height = 0;

	// templates
	this.templates = {
		'container-start' : '<div class="os3_tabs">',
		'container-end' : '</div>',
		'header-start' : '<div class="os3tabs_header" id="%(_prefix)s_header">',
		'header-end' : '</div>',
		'body-start' : '<div class="os3tabs_body" id="%(_prefix)s_body">',
		'body-end' : '</div>',
		'group-start' : '<div id="%(tab-row-id)s" class="row">',
		'group-end' : '</div>',
		'tabs' : '<div class="tab" id="%(id)s" %(events)s style="%(style)s">%(title)s</div>',
		'tabs-body' : '<div class="tab" id="%(id)s">%(content)s</div>'
	};

	this.render = function ( dest_div )
	{
		var t, l = this._group_names.length;
		var grp;
		var s = '', ss;
		var header;
		var style = '';
		var rows = 0;
		var self = this;

		if ( ! $( this._prefix + '_header' ) )
		{
			var base_html = new String.buffer ();

			/*
			base_html.add ( '<div class="os3_tabs">' );
			base_html.add ( '<div class="os3tabs_header" id="' + this._prefix + '_header"></div>' );
			base_html.add ( '<div class="os3tabs_body" id="' + this._prefix + '_body">' );
			*/
			base_html.add ( String.formatDict ( this.templates [ 'container-start' ], this ) );
			base_html.add ( String.formatDict ( this.templates [ 'header-start' ], this ) );
			base_html.add ( String.formatDict ( this.templates [ 'header-end' ], this ) );
			base_html.add ( String.formatDict ( this.templates [ 'body-start' ], this ) );

			this._divs_html.iterate ( function ( v, k ) {
					var s;
					//s = String.format ( '<div class="tab" id="%s">%s</div>', v [ 0 ], ( v [ 1 ] ? v [ 1 ] : "" ) );
					var params = {
						'id' : v [ 0 ],
						'content' : ( v [ 1 ] ? v [ 1 ] : "" )
					};
					s = String.formatDict ( self.templates [ 'tabs-body' ], params );
					base_html.add ( s );
				} );

			//base_html.add ( '</div></div>' );
			base_html.add ( String.formatDict ( this.templates [ 'body-end' ], this ) );
			base_html.add ( String.formatDict ( this.templates [ 'container-end' ], this ) );

			if ( dest_div ) $( dest_div, base_html.toString () );
		}

		for ( t = 0; t < l; t ++ )
		{
			grp = this._tabs [ this._group_names [ t ] ];
			if ( ! grp.length ) continue;
			rows ++;
			s += this._render_grp ( grp, this._group_names [ t ] );
		}

		header = $( this._prefix + '_header' );

		if ( ! header )
		{		
			console.warn ( "OS3Tabs: ERROR: Could not find: %s div for headers", this._prefix + "_header" );
			return;
		}
		if ( this.tab_height ) header.style.height = this._calc_header_height ( rows );

		header.innerHTML = s;
	};

	this._calc_header_height = function ( rows )
	{
		var split = this.tab_height.split ( /(mm|px|pt|ex|em|%)/i );
		if ( split.length < 2 ) return "";

		var v = parseInt ( split [ 0 ] );
		var mis = split [ 1 ];
		var res = ( v * rows ) + mis;

		return res;
	};

	this.set_tab_title = function ( title, group_name, pos )
	{
		var id = this._mk_tab_id ( this._prefix, group_name, pos );
		var d = document.getElementById ( id );

		d.innerHTML = title;
	};

	this.get_tab_pos = function ( div_name, group_name )
	{
		var divs = this._divs_ref;
		var pos = -1;

		divs.iterate ( function ( v, k )
		{
			if ( pos != -1 ) return;

			if ( k == div_name )
			{
				pos = parseInt ( v.split ( ":" ).slice ( -1 ) [ 0 ], 10 );
			}
		} );

		return pos;
	};

	this.block_event = function ( event_name, mode )
	{
		if ( mode === undefined ) mode = true;
		this._blocked_events [ event_name ] = mode;
	};

	this._render_grp = function ( grp, grp_name )
	{
		var t, l, s = '', events, events_meta, id, style = '';
		var gname;
		var self = this;

		l = grp.length;

		var params = this._group_params.get ( grp_name, {} );
		params [ 'group-name' ] = grp_name;
		params [ 'tab-row-id' ] = this._mk_tab_row_id ( this._prefix, grp_name );

		//s += '<div id="' + this._mk_tab_row_id ( this._prefix, grp_name ) + '" class="row" >';
		s += String.formatDict ( this.templates [ 'group-start' ], params );

		if ( this.tab_width ) style += 'width: ' + this.tab_width;

		//if ( style ) style = ' style="' + style + '" ';

		events_meta = "'" + this._prefix + "','" + grp_name + "'";
		for ( t = 0; t < l; t ++ )
		{
			events  = "onmouseover=\"OS3Tabs.evt(this,'hover'," + events_meta + "," + t + ")\" ";
			events += "onmouseout=\"OS3Tabs.evt(this,'out'," + events_meta + "," + t + ")\" ";
			events += "onmousedown=\"OS3Tabs.evt(this,'btn_down'," + events_meta + "," + t + ")\" ";
			events += "onmouseup=\"OS3Tabs.evt(this,'btn_up'," + events_meta + "," + t + ")\" ";
			events += "onclick=\"OS3Tabs.evt(this,'click'," + events_meta + "," + t + ")\" ";
			events += "ondblclick=\"OS3Tabs.evt(this,'dblclick'," + events_meta + "," + t + ")\" ";
			//id=' id="' + this._mk_tab_id ( this._prefix, grp_name, t ) + '" ';

			//s += '<div class="tab" ' + id + events + style + '>' + grp [ t ] + '</div>';
			var params = {
				'id' : this._mk_tab_id ( this._prefix, grp_name, t ),
				'events' : events,
				'style' : style,
				'title' : grp [ t ]
			};
			s += String.formatDict ( self.templates [ 'tabs' ], params );
		}
		//s += '</div>';
		s += String.formatDict ( this.templates [ 'group-end' ], params );
		delete this [ 'tab-row-id' ];

		return s;
	}

	this._mk_tab_row_id = function ( prefix, grp_name )
	{
		return prefix + ":" + grp_name + ":tab_row";
	};

	this._mk_tab_id = function ( prefix, grp_name, pos )
	{
		return prefix + ":" + grp_name + ":" + pos;
	};

	this.set_event = function ( evt_name, cback )
	{
		this._events [ evt_name ] = cback;
	};

	this.clear = function ()
	{
		this._tabs    = { 'default' : [] };
		this._tabs_ref = {};
		this._tabs_names_ref = {};
		this._divs_ref = {};
		this._group_names = [ 'default' ];	// Group names (in order)
		this._curr_group = this._tabs [ 'default' ];
		this._curr_group_name = 'default';
	};

	// {{{ set_group ( group_name )
	this.set_group = function ( group_name )
	{
		if ( ! this._tabs [ group_name ] )
		{
			this._group_names.push ( group_name );
			this._tabs [ group_name ] = [];
		}

		this._curr_group = this._tabs [ group_name ];
		this._curr_group_name = group_name;
	};
	// }}}
	// {{{ add ( title, div_name )
	this.add = function ( title, div_name, html_content, hidden )
	{
		var pos = this._curr_group.length;
		var id = this._mk_tab_id ( this._prefix, this._curr_group_name, pos );

		if ( ! hidden ) this._curr_group.push ( title );
		this._tabs_ref [ id ] = null; // document.getElementById ( div_name );
		this._tabs_names_ref [ id ] = div_name;

		this._divs_ref [ div_name ] = id;

		this._divs_html.push ( [ div_name, html_content ] );
	};
	// }}}

	this.send_event = function ( tab_name, evt )
	{
		var id = this._divs_ref [ tab_name ];
		var div = document.getElementById ( id );

		this._curr_tab = div;
		OS3Tabs.evt ( div, evt, this._prefix );
	};

	this.enable_tab = function ( div_name, enable )
	{
		var id = this._divs_ref [ div_name ];
		var div = document.getElementById ( id );

		if ( ! div [ "_disabled" ] && enable ) return;
		if ( div [ "_disabled" ] && ! enable ) return;

		if ( enable )
		{
			div._disabled = false;
			div.className = "tab";
		}
		else
		{
			div._disabled = true;
			div.className = "disabled";
		}
	};

	this.set_group_param = function ( group_name, key, value )
	{
		if ( ! this._group_params.get ( group_name ) )
			this._group_params [ group_name ] = {};
		this._group_params [ group_name ] [ key ] = value;
	};
	
	this.set_group_params = function ( group_name, values )
	{
		var self = this;

		values.iterate ( function ( v, k )
		{
			self.set_group_param ( group_name, k, v );
		} );
	};

	OS3Tabs._instances [ this._prefix ] = this;
};

